package top.hekun.study.core.visitor.method.complex;

import org.objectweb.asm.MethodVisitor;

import static org.objectweb.asm.Opcodes.*;

/**
 * 〈自己给自己赋值的代码〉 this.var=this.var;
 *
 * @author: Sakura
 * @date: 2023/5/13
 */
public class MyMethodVisitor2 extends PatternMethodVisitor {
    private String thisClassName = this.getClass().getSimpleName();

    /**
     * this.var=this.var;
     * <p>
     * 加载this 加载this 消耗一个this 兵获取字段 消耗一个this 和上一步获取的字段, 并执行字段赋值
     */
    protected final static int SEEN_ALOAD_0 = 1;
    protected final static int SEEN_ALOAD_0_ALOAD_0 = 2;
    protected final static int SEEN_ALOAD_0_ALOAD_0_GETFIELD = 3;
    // 当执行到 最后一个状态的时候 就回归到原始状态
    protected final static int SEEN_ALOAD_0_ALOAD_0_GETFIELD_PUTFIELD = SEEN_NOTHING;
    String fieldOwner;
    String fieldName;
    String fieldDescriptor;

    protected MyMethodVisitor2(int api, MethodVisitor methodVisitor) {
        super(api, methodVisitor);
    }

    /**
     * 去掉 this.var=this.var; 在 这个方法中 进行方法的变化
     *
     * @param opcode
     */
    @Override
    public void visitVarInsn(int opcode, int varIndex) {
        switch (state) {
            // 初始状态下
            case SEEN_NOTHING:
                if (opcode == ALOAD && varIndex == 0) {
                    state = SEEN_ALOAD_0;
                    return;
                }
                break;
            case SEEN_ALOAD_0:
                if (opcode == ALOAD && varIndex == 0) {
                    state = SEEN_ALOAD_0_ALOAD_0;
                    return;
                }
                break;
            case SEEN_ALOAD_0_ALOAD_0:
                if (opcode == ALOAD && varIndex == 0) {
                    mv.visitVarInsn(opcode, varIndex);
                    return;
                }
                break;

        }
        super.visitVarInsn(opcode, varIndex);
    }

    @Override
    public void visitFieldInsn(int opcode, String owner, String name, String descriptor) {
        switch (state) {
            // 初始状态下
            case SEEN_ALOAD_0_ALOAD_0:
                if (opcode == GETFIELD ) {
                    state = SEEN_ALOAD_0_ALOAD_0_GETFIELD;
                    fieldOwner = owner;
                    fieldName = name;
                    fieldDescriptor = descriptor;
                    return;
                }
                break;
            case SEEN_ALOAD_0_ALOAD_0_GETFIELD:
                if (opcode == PUTFIELD && fieldName.equals(name)) {
                    state = SEEN_NOTHING;
                    return;
                }
                break;
        }
        super.visitFieldInsn(opcode, owner, name, descriptor);
    }

    /**
     * 兼职状态的初始化
     *  状态的回归
     */
    @Override
    public void visitInsn() {
//        System.out.println("state: " + state);
        switch (state) {
            case SEEN_ALOAD_0:
                mv.visitVarInsn(ALOAD,0);
                break;
            case SEEN_ALOAD_0_ALOAD_0:
                mv.visitVarInsn(ALOAD,0);
                mv.visitVarInsn(ALOAD,0);
                break;
            case SEEN_ALOAD_0_ALOAD_0_GETFIELD:
                mv.visitVarInsn(ALOAD,0);
                mv.visitVarInsn(ALOAD,0);
                mv.visitFieldInsn(GETFIELD,fieldOwner,fieldName,fieldDescriptor);
                break;
        }
        //  首次进入的时候  赋值 state= SEEN_NOTHING
        state = SEEN_NOTHING;
    }
}
